﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Text.RegularExpressions;

using Danser_AJAXEnabledWebApplication.Faults;
using Danser_AJAXEnabledWebApplication.User_Controls;
using Danser_Control.Managers;
using Danser_Entity.Entities;

namespace Danser_AJAXEnabledWebApplication
{
    /// <summary>
    /// Page for the Uploading new test data files
    /// </summary>
    public partial class UploadNewDataNew : AbstractPage
    {
        #region Members:

        /// <summary>
        /// The logic data source to bind to the grid View
        /// </summary>
        DataTable _table;

        /// <summary>
        /// Holds all files user selected to upload
        /// </summary>
        IDictionary<string, HttpPostedFile> _filesToUpload;

        /// <summary>
        /// Path to folder the files wre uploaded to
        /// </summary>
        String _tmpDirectoryPath = Danser_Control.Properties.Settings.Default.UploadTmpFolder;

        #region Constants:

        private const String FILES_TABLE_KEY = "filesTable";
        private const String TO_UPLOAD_KEY = "toUpload";

        #endregion

        #endregion

        #region Constants:

        //data table columns' names
        private const String FILES_COL = "Files";
        private const String STATUS_COL = "Status";
        private const String COMMENT_COL = "Comments";

        private const String STATUS_SUCCESS = "Succeeded";
        private const String STATUS_FAILED = "Failed";

        private const String UPLOAD_EXECUTED = "UploadFilesExecuted";

        #endregion

        #region Page Load:

        /// <summary>
        /// loads the page...
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected override void Page_Load(object sender, EventArgs e)
        {
            base.Page_Load(sender, e);

            if (!Page.IsPostBack) //first time:
            {
                InitializeDataSources();
  
                //Bind available validation templates                
                PopulateValidationsList(multiSelectList);
            }
        }

        #endregion

        #region FilesTable:

        /// <summary>
        /// event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void addRow_click(object sender, EventArgs e)
        {
            //clear data sources if last action was uploading previouse files
            if (Convert.ToBoolean(Session[UPLOAD_EXECUTED]))
            {
                InitializeDataSources();
            }

            string fileName = this.FileUpload.PostedFile.FileName;

            //ignore if fileUpload box is empty 
            if (String.IsNullOrEmpty(fileName))
                return;

            _table = Session[FILES_TABLE_KEY] as DataTable;
            _filesToUpload = Session[TO_UPLOAD_KEY] as IDictionary<string, HttpPostedFile>;

            _filesToUpload[fileName] = this.FileUpload.PostedFile;

            //addnewRowToTable:
            DataRow row = _table.NewRow();
            row[FILES_COL] = fileName;

            _table.Rows.Add(row);

            //refresh control:
            filesGridView.DataSource = _table.DefaultView;
            filesGridView.DataBind();

            uploadPanel.Visible = true;
        }

        /// <summary>
        /// Create the data table used to support the files grid view
        /// </summary>
        /// <returns></returns>
        private DataTable CreateDataTable()
        {
            DataTable myDataTable = new DataTable();
            DataColumn myDataColumn = null;

            myDataColumn = new DataColumn();
            myDataColumn.DataType = Type.GetType("System.String");
            myDataColumn.ColumnName = FILES_COL;
            myDataTable.Columns.Add(myDataColumn);

            myDataColumn = new DataColumn();
            myDataColumn.DataType = Type.GetType("System.String");
            myDataColumn.ColumnName = STATUS_COL;
            myDataTable.Columns.Add(myDataColumn);

            myDataColumn = new DataColumn();
            myDataColumn.DataType = Type.GetType("System.String");
            myDataColumn.ColumnName = COMMENT_COL;
            myDataTable.Columns.Add(myDataColumn);

            return myDataTable;
        }

        #endregion

        #region Controls Event Handlers:

        /// <summary>
        /// event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void uploadButton_Click(object sender, EventArgs e)
        {
            uploadingFilesPanel.Visible = true;
            
            uploadFiles();

            uploadingFilesPanel.Visible = false;
        }

        /// <summary>
        /// event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void cancelButton_Click(object sender, EventArgs e)
        {
            _table = Session[FILES_TABLE_KEY] as DataTable;
            _filesToUpload = Session[TO_UPLOAD_KEY] as IDictionary<string, HttpPostedFile>;

            if (_table != null)
            {
                _table.Clear();
                filesGridView.DataSource = _table.DefaultView;
                filesGridView.DataBind();
            }
            if (_filesToUpload != null)
                _filesToUpload.Clear();

            uploadPanel.Visible = false;
        }

        #endregion

        #region Grid Handlers:

        /// <summary>
        /// event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void filesGridView_RowDataBound(object sender, GridViewRowEventArgs e)
        {
            GridViewRow row = e.Row;
            for (int i = 1; i < row.Cells.Count; i++)
            {
                TableCell cell = row.Cells[i];
                double cellWidth = i == 1 ? 100 : 400;
                cell.Width = new Unit(cellWidth, UnitType.Pixel);
                cell.BorderColor = Color.White;
                cell.BorderStyle = BorderStyle.Solid;
                cell.BorderWidth = new Unit(1, UnitType.Pixel);

            }
            //paint status column for data rows
            if (row.RowType == DataControlRowType.DataRow)
            {
                TableCell statusCell = row.Cells[1];
                statusCell.ForeColor = 
                    statusCell.Text.Equals(STATUS_SUCCESS) ? 
                    Color.Green :
                    Color.Red;
            }
        }

        /// <summary>
        /// event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void filesGridView_PageIndexChanging(object sender, GridViewPageEventArgs e)
        {
            filesGridView.PageIndex = e.NewPageIndex;
            _table = Session[FILES_TABLE_KEY] as DataTable;
            filesGridView.DataSource = _table;
            filesGridView.DataBind();
        }

        #endregion

        #region Heplers:

        /// <summary>
        /// Upload files saved in cash (Session)
        /// </summary>
        private void uploadFiles()
        {
            Session[UPLOAD_EXECUTED] = "true";

            //0. add '\' if missing at the end of the directory path
            _tmpDirectoryPath = 
                _tmpDirectoryPath.EndsWith("\\") ?
                _tmpDirectoryPath : 
                _tmpDirectoryPath + "\\";

            //1. get the data out of the session, and upload it to server.

            _filesToUpload = (Dictionary<string, HttpPostedFile>)Session[TO_UPLOAD_KEY];

            //list to save paths
            IList<String> filesPathList = new List<String>(_filesToUpload.Count);

            foreach (HttpPostedFile fileToLoad in _filesToUpload.Values)
            {
                string fileName = formatFileName(fileToLoad);
                //save the file path for control layer
                filesPathList.Add(_tmpDirectoryPath + fileName);
                try
                {
                    fileToLoad.SaveAs(_tmpDirectoryPath + fileName);
                }
                catch (Exception e)//HttpException
                {
                    HandleGenericErrorPage(e);
                }
            }

            //get list of validations to run on files (besides the default ones)
            IList<int> validationIds = ExtractValidationIds(multiSelectList);

            try
            {
                //2. call the Danser_Control to parse the files and enter to database.
                IDataManager dataManager = ManagerFactory.DataManager();

                //3. get the result with status and comments, and update table

                IList<ValidationResult> validationResults =
                        dataManager.UploadInput(filesPathList, validationIds);

                //4. populate files table according to results
                _table = Session[FILES_TABLE_KEY] as DataTable;

                //validation results are synchronized with rows in table
                for (int i = 0; i < _table.Rows.Count; i++)
                {
                    _table.Rows[i][STATUS_COL] =
                        validationResults[i]._isUploaded ? STATUS_SUCCESS : STATUS_FAILED;
                    _table.Rows[i][COMMENT_COL] = validationResults[i]._comment;
                }
            }
            catch (Exception e)
            {
                HandleGenericErrorPage(e);
            }

            //rebind grid
            filesGridView.DataSource = _table.DefaultView;
            filesGridView.DataBind();
            
            //hide upload panel
            uploadPanel.Visible = false;
        }

        /// <summary>
        /// Gets the file name + extension from the posted file. 
        /// <para>Needed to parse file name for Internet Explorer v 6.0 and bellow</para>
        /// </summary>
        /// <param name="fileToLoad">The file posted in FileUpload box</param>
        /// <returns>The file name + 3 characters extension</returns>
        private string formatFileName(HttpPostedFile fileToLoad)
        {

            //taken from http://www.aspnettutorials.com/tutorials/network/net-fileupload-aspnet2-csharp.aspx
            string filepath = fileToLoad.FileName;
            string file = filepath;

            string pattern = @"\\(?:.+)\\(.+)\.(.+)";
            Regex regExp = new Regex(pattern);

            //run
            Match match = regExp.Match(filepath);
            if (!String.IsNullOrEmpty(match.Value))
            {
                string file_ext = match.Groups[2].Captures[0].ToString();
                string filename = match.Groups[1].Captures[0].ToString();
                file = filename + "." + file_ext;
            }
            return file;

        }

        /// <summary>
        /// Populates the validations list with all the non default validations (name and id) 
        /// so user can select them for the uploading process
        /// </summary>
        /// <param name="validationsList">The list to populate</param>
        private void PopulateValidationsList(MultiSelectList validationsList)
        {
            IValidationManager manager = ManagerFactory.ValidationManager();
            IList<ValidationTemplate> allTemplates = manager.GetValidationTemplates((IList<int>)null);

            foreach (ValidationTemplate template in allTemplates)
            {
                ListItem item = new ListItem(template.Name + " (" + template.ID + ")");

                //default templates are displayed but without possibility of cselection
                if (template.AppliedOnDefault)
                {
                    item.Enabled = false;
                    item.Selected = true;
                }

                validationsList.Items.Add(item);
            }
        }

        /// <summary>
        /// Extracts out of the list all selected validation ids to send to control layer
        /// </summary>
        /// <param name="validationslist">The list consisting of the selescted validations</param>
        /// <returns>list of ids</returns>
        private IList<int> ExtractValidationIds(MultiSelectList validationslist)
        {
            IList<int> validationIds = new List<int>(validationslist.Items.Count);

            foreach (ListItem selectedItem in validationslist.SelectedItems)
            {
                String selectedValue = selectedItem.Value;

                //array of 2 elements - first is the name, second is the id
                String[] validationData =
                    selectedValue.Split(
                        new char[] { '(', ')' },
                        StringSplitOptions.RemoveEmptyEntries);

                validationIds.Add(Convert.ToInt32(validationData[1]));
            }

            return validationIds;
        }

        /// <summary>
        /// clears data sources
        /// </summary>
        private void InitializeDataSources()
        {
            //reset session variable
            Session[UPLOAD_EXECUTED] = "false";

            //construct the data sources
            _filesToUpload = new Dictionary<string, HttpPostedFile>();
            _table = CreateDataTable();

            //addjust GridView:
            Session[FILES_TABLE_KEY] = _table;
            Session[TO_UPLOAD_KEY] = _filesToUpload;

            //bind the grid
            filesGridView.DataSource = ((DataTable)Session[FILES_TABLE_KEY]).DefaultView;
            filesGridView.DataBind();
        }

        #endregion

        #region AbstractPage Implementation:

        /// <see cref="Danser_AJAXEnabledWebApplication.AbstractPage.InnerValidatePermission"/>
        protected override bool InnerValidatePermission(PermissionLevel permissionlevel)
        {
            //everyone but the Viewer level
            return permissionlevel != PermissionLevel.Viewer;
        }

        #endregion

     }
}
